package mskruch.gps.experimental;

import gpstools.math.GeoCalculations;
import mskruch.gps.Point;
import mskruch.gps.Position;

/**
 * 
 * @author Slawomir.Przednowek Elevation calculator based on local extrema
 * 
 */
public class SecondCalculator {

    private Point[] points = null;

    public void setPoints(Point[] points) {
        this.points = points;
    }

    public SecondCalculator(Point[] points) {
        setPoints(points);
    }

    private boolean isLocalExtrema(Point[] points, int index) {
        boolean lowerFound = false, higherFound = false;
        for (int i = -5; i <= 5; i++) {
            if (index + i < 0 || i == 0) {
                continue;
            }
            if (index + i >= points.length) {
                break;
            }
            if (points[index + i].getElevation() < points[index].getElevation()) {
                lowerFound = true;
            } else if (points[index + i].getElevation() > points[index].getElevation()) {
                higherFound = true;
            }

            if (i < 0 && points[index + i].getElevation() == points[index].getElevation()) {
                lowerFound = true;
                higherFound = true;
            }
        }
        return !(higherFound && lowerFound);
    }

    public Double getDistance() {
        Position[] extractedPoints = points;

        Position previousPoint = null;
        double totalDist = 0.0;
        for (int i = 0; i < extractedPoints.length; i++) {

            Position currentPoint = (Position) extractedPoints[i];
            if (previousPoint == null) {
                previousPoint = currentPoint;
            } else {
                double currDist = GeoCalculations.distance(previousPoint.getLatitude(), previousPoint.getLongitude(),
                        currentPoint.getLatitude(), currentPoint.getLongitude());
                totalDist += currDist;
                previousPoint = currentPoint;
            }
        }

        double totalAscent = getElevationGain();
        double totalDescent = getElevationLoss();
        return Math.sqrt(totalDist * totalDist + Math.pow((totalAscent + totalDescent) / 1000.0, 2.0));
    }

    public Double getElevationGain() {
        Point[] extractedPoints = points;
        Point previousPoint = null;
        double totalAscent = 0.0;
        for (int i = 0; i < extractedPoints.length; i++) {
            Point currentPoint = (Point) extractedPoints[i];
            if (previousPoint == null) {
                previousPoint = currentPoint;
            } else {
                double currAscent = currentPoint.getElevation() - previousPoint.getElevation();

                if (isLocalExtrema(extractedPoints, i)) {
                    if (currAscent > 0) {
                        previousPoint = currentPoint;
                        totalAscent += currAscent;

                    } else {
                        previousPoint = currentPoint;
                    }
                }
            }
        }
        return totalAscent;
    }

    public Double getElevationLoss() {
        //TODO implement
        Point first = points[0];
        Point last = points[points.length-1];
        return getElevationGain() - (last.getElevation() - first.getElevation());
    }

}
